package academic.emailClient.persistence;

import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.UUID;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;



import academic.emailClient.model.entities.Meeting;
import academic.emailClient.model.entities.MeetingBuilder;

/**
 * Class that implements how meetings are persisted
 * @author Alejandra
 *
 */
public class MeetingFileDAO {
	
	private static String path = "." + File.separator + "Meetings";
	private static final String DATE_FORMAT = "yyMMddHHmmss"; 
	private static DateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
	private static String LOCATION = "location";
	private static String MEETING = "meeting";
	private static String PURPOSE = "purpose";
	private static String DESCRIPTION = "description";
	private static String START = "start";
	private static String END = "end";
	private static String ATTENDEES = "attendees";
	private static String ATTENDEE = "attendee";
	private static String DURATION = "duration";
	private static String OWNER = "owner";
	private static String VERSION = "version";
	
	/**
	 * Persists a meeting as an xml file
	 * @param meeting Meeting object
	 * @return True if the file can be written
	 * @throws RuntimeException Exceptions caused by the use of DOM parser
	 */
	public static boolean write(Meeting meeting) throws RuntimeException{
		try {						
			
			//Document instatiation
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();
			
			//Root
			Document document = builder.newDocument();
			Element rootElement = document.createElement(MEETING);
			document.appendChild(rootElement);
			
			//Creates values
			Element version = document.createElement(VERSION);
			version.appendChild(document.createTextNode(Integer.toString(meeting.getVersion())));
			rootElement.appendChild(version);
			
			Element owner = document.createElement(OWNER);
			owner.appendChild(document.createTextNode(meeting.getOwner()));
			rootElement.appendChild(owner);
			
			Element location = document.createElement(LOCATION);
			location.appendChild(document.createTextNode(meeting.getLocation()));
			rootElement.appendChild(location);
			
			Element attendees = document.createElement(ATTENDEES);
			rootElement.appendChild(attendees);
			for (String attendeeMail : meeting.getAttendees()){
				Element attendee = document.createElement(ATTENDEE);
				attendee.appendChild(document.createTextNode(attendeeMail));
				attendees.appendChild(attendee);				
			}
			
			Element purpose = document.createElement(PURPOSE);
			purpose.appendChild(document.createTextNode(meeting.getPurpose()));
			rootElement.appendChild(purpose);
			
			Element description = document.createElement(DESCRIPTION);
			description.appendChild(document.createTextNode(meeting.getDescription()));
			rootElement.appendChild(description);
			
			Element start = document.createElement(START);
			start.appendChild(document.createTextNode(dateFormat.format(meeting.getStart())));
			rootElement.appendChild(start);
			
			Element end = document.createElement(END);
			end.appendChild(document.createTextNode(dateFormat.format(meeting.getEnd())));
			rootElement.appendChild(end);
			
			Element duration = document.createElement(DURATION);
			duration.appendChild(document.createTextNode(Integer.toString(meeting.getDuration())));
			rootElement.appendChild(duration);
			
			//Transforms the document java with 
			TransformerFactory transFactory = TransformerFactory.newInstance();
			Transformer transformer = transFactory.newTransformer();
			//DOM Parser to convert document
			DOMSource source = new DOMSource(document);
			
			//parsing source to result
			StreamResult result = new StreamResult(new File(path, meeting.getId().toString()));
			transformer.transform(source, result);			
			
			return true;
			
		}
		catch (ParserConfigurationException e){
			throw new RuntimeException(e);
		}
		catch (TransformerConfigurationException tce){
			throw new RuntimeException(tce);
		}
		catch (TransformerException te){
			throw new RuntimeException(te);
		}		
	}
	
	/**
	 * Reads a list of meetings persisted in a file directory
	 * @return HashMap<Meeting ID, Meeting>
	 */
	public static HashMap<UUID, Meeting> read(){
		HashMap<UUID, Meeting> meetings = new HashMap<UUID, Meeting>();
		File meetingDirectory = new File(path);
		String[] fileNames = meetingDirectory.list();
		try {
			DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = docFactory.newDocumentBuilder();		

			
			for (String fileName : fileNames){
				File file = new File(path, fileName); 
				Document source = docBuilder.parse(file);
				Element meetingInfo = (Element) source.getElementsByTagName(MEETING).item(0);
				
				
				//Date date
				Date start = dateFormat.parse(meetingInfo.getElementsByTagName(START).item(0).getTextContent());
				Date end = dateFormat.parse(source.getElementsByTagName(END).item(0).getTextContent());
				
				//Attendees
				ArrayList<String> attendees = new ArrayList<String>();
				Element attendeesGroup = (Element) meetingInfo.getElementsByTagName(ATTENDEES).item(0);
				NodeList attendeesInfo = attendeesGroup.getElementsByTagName(ATTENDEE);
				for (int i=0; i<attendeesInfo.getLength(); i++){
					attendees.add(attendeesInfo.item(i).getTextContent());
				}
				
				//Meeting construction				
				MeetingBuilder meeting = new MeetingBuilder();
				Meeting newMeeting = meeting.withId(UUID.fromString(fileName))
											.withVersion
												(Integer.parseInt(meetingInfo.getElementsByTagName(VERSION).item(0).getTextContent()))
											.withOwner
												(meetingInfo.getElementsByTagName(OWNER).item(0).getTextContent())
											.withLocation
												(meetingInfo.getElementsByTagName(LOCATION).item(0).getTextContent())
											.withPurpose
												(meetingInfo.getElementsByTagName(PURPOSE).item(0).getTextContent())
											.withDescription
												(meetingInfo.getElementsByTagName(DESCRIPTION).item(0).getTextContent())
											.withDuration(Integer.parseInt(meetingInfo.getElementsByTagName(DURATION).item(0).getTextContent()))
											.withAttendees(attendees)
											.withStart(start)
											.withEnd(end)											
											.build();
				meetings.put(newMeeting.getId(), newMeeting);				
			}
		}
		catch (ParserConfigurationException pce){
			throw new RuntimeException(pce);
		}
		catch (Exception e){
			throw new RuntimeException(e);
		}

		return meetings;
	}
		
	/**
	 * Deletes a meeting from the persistence source
	 * @param meeting Meeting to delete, should be built
	 * @return True if meeting can be deleted
	 */
	public static boolean delete(UUID meetingID){
		File file = new File(path, meetingID.toString());
		return file.delete();
	}
}
